package com.echronos.payment.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.echronos.commons.Result;
import com.echronos.commons.exception.BusinessException;
import com.echronos.commons.model.AppThreadLocal;
import com.echronos.commons.model.BaseModel;
import com.echronos.commons.utils.RequestUserUtils;
import com.echronos.payment.annotation.PayChannelInterfaceHandler;
import com.echronos.payment.commons.cpcn.config.ReceiveNoticeHandler;
import com.echronos.payment.commons.cpcn.enums.CpcnPayStatusEnums;
import com.echronos.payment.commons.cpcn.enums.CpcnSmsVerifyStatusEnums;
import com.echronos.payment.commons.cpcn.enums.ReceiveNoticeEnums;
import com.echronos.payment.commons.cpcn.strategy.ReceiveNoticeStrategy;
import com.echronos.payment.commons.cpcn.util.*;
import com.echronos.payment.enums.ChannelRouteInterfaceTypeEnums;
import com.echronos.payment.enums.PayResultEnums;
import com.echronos.payment.manager.PaymentPayLogManager;
import com.echronos.payment.manager.SupportCpcnMchBindAppManager;
import com.echronos.payment.manager.SupportCpcnMchManager;
import com.echronos.payment.manager.SupportCpcnSmsVerifyManager;
import com.echronos.payment.model.PaymentPayLog;
import com.echronos.payment.model.SupportCpcnMch;
import com.echronos.payment.model.SupportCpcnSmsVerify;
import com.echronos.payment.param.post.SupportCpcnBankCardSmsVerifyParam;
import com.google.common.collect.Lists;
import cpcn.institution.tools.util.Base64;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Service;
import payment.api.notice.NoticeRequest;
import payment.api.notice.NoticeResponse;
import payment.api.system.PaymentEnvironment;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 中金支付相关
 *
 * @Author wangyadong
 * @Date 2023/11/17 11:37
 * @ClassName IPayCpcnPayService
 */
@Slf4j
@Service
@PayChannelInterfaceHandler(value = ChannelRouteInterfaceTypeEnums.CPCN_INTERFACE)
public class IPayCpcnPayService {
    /**
     * 数据源编码
     */
    @Value("${cpcn.default-source-code}")
    private String sourceCode;

    @Resource
    private SupportCpcnMchManager cpcnMchManager;

    @Resource
    private PaymentPayLogManager payLogManager;

    @Resource
    private SupportCpcnMchBindAppManager mchBindAppManager;

    @Resource
    private SupportCpcnSmsVerifyManager smsVerifyManager;

    /**
     * 当前执行中金商户
     */
    public SupportCpcnMch getCpcnMch(String fromTenantId) {
        String tenantId = AppThreadLocal.getTenantId();
        if (StringUtils.isNotEmpty(fromTenantId)) {
            tenantId = fromTenantId;
        }
        return cpcnMchManager.getOne(new LambdaQueryWrapper<SupportCpcnMch>()
                .eq(BaseModel::getTenantId, tenantId)
        );
    }

    /**
     * 中金快捷支付短信验证
     *
     * @param param
     */
    public Result smsVerifyBankCardPay(SupportCpcnBankCardSmsVerifyParam param) {
        SupportCpcnMch cpcnMch = getCpcnMch(param.getTenantId());
        if (ObjectUtils.isNull(cpcnMch)) {
            throw new BusinessException(50004, "该站点暂无收款商户信息！");
        }
        PaymentPayLog payLog = payLogManager.getOne(new LambdaQueryWrapper<PaymentPayLog>()
                .eq(PaymentPayLog::getTradeNo, param.getPayTradeNo())
        );
        if (ObjectUtils.isNull(payLog)) {
            throw new BusinessException(50004, "无支付流水信息！");
        }
        if (payLog.getPayResult().equals(PayResultEnums.PAY_SUCCESS.getCode())) {
            return Result.build();
        }
        CpcnTx5015Model model = new CpcnTx5015Model();
        model.setInstitutionID(cpcnMch.getMchId());
        model.setTxSN(payLog.getTradeNo());
        model.setSmsValidationCode(param.getVerifyCode());
        CpcnTx5015Request request = new CpcnTx5015Request();
        request.setBizModel(model);
        CpcnClient ccbClient = new CpcnAbstractClient(cpcnMch.getMchId());
        CpcnTx5015Response execute = ccbClient.execute(request);
        log.info("快捷支付短信验证返回结果response：{}", JSONObject.toJSONString(execute));
        if (!execute.getIsSuccess()) {
            return Result.build(80005, execute.getMessage());
        }
        SupportCpcnSmsVerify smsVerify = new SupportCpcnSmsVerify();
        smsVerify.setCompanyId(RequestUserUtils.getUser().getCompanyId());
        smsVerify.setVerifyCode(param.getVerifyCode());
        smsVerify.setVerifyType(10);
        smsVerify.setMerchantId(cpcnMch.getId());
        smsVerify.setSendNo(param.getPayTradeNo());
        smsVerify.setPhone(RequestUserUtils.getUser().getPhone());
        smsVerify.setStatus(Integer.valueOf(execute.getVerifyStatus()));
        smsVerifyManager.saveOrUpdate(smsVerify);
        ArrayList<String> smsStatusList = Lists.newArrayList(CpcnSmsVerifyStatusEnums.UN_PASSAGE.getStatusCode(),
                CpcnSmsVerifyStatusEnums.TIME_OUT.getStatusCode());
        if (smsStatusList.contains(execute.getVerifyStatus())) {
            return Result.build(50023, execute.getResponseMessage());
        }
        ArrayList<String> payStatusList = Lists.newArrayList(CpcnPayStatusEnums.PAY_FAILED.getStatusCode(),
                CpcnPayStatusEnums.PAY_CANCEL.getStatusCode());
        if (payStatusList.contains(execute.getStatus())) {
            return Result.build(50033, execute.getResponseMessage());
        }
        return Result.build();
    }

    private Map<ReceiveNoticeEnums, ReceiveNoticeStrategy> strategyMap = new HashMap<>();

    @Resource
    private void setStrategyMap(List<ReceiveNoticeStrategy> strategies) {
        strategies.stream().forEach(r -> {
            ReceiveNoticeHandler annotation = AnnotationUtils.findAnnotation(r.getClass(), ReceiveNoticeHandler.class);
            if (ObjectUtils.isNotNull(annotation)) {
                strategyMap.put(annotation.value(), r);
            }
        });
    }

    /**
     * 中金相关接口推送通知
     * 可配置多商户接收
     * 根据路径uri
     *
     * @param request
     * @param response
     */
    public void receiveNotify(HttpServletRequest request, HttpServletResponse response) {
        try {
            log.info("========== Begin [Cpcn receiveNotify] process ==========");
            String requestURI = request.getRequestURI();
            // 1 获得参数message和signature
            String message = request.getParameter("message");
            String signature = request.getParameter("signature");
            String isDgEnv = request.getParameter("isDgEnv");
            String digitalEnvelope = request.getParameter("digitalEnvelope");
            String signAlgorithm = request.getParameter("signAlgorithm");
            String signSN = request.getParameter("signSN");
            String encryptSN = request.getParameter("encryptSN");
            String institutionID = requestURI.substring(requestURI.lastIndexOf("/") + 1);
            log.info("receiveNotify institutionID:{}", institutionID);
            log.info("receiveNotify message:{}", message);
            log.info("receiveNotify signature:{}", signature);
            log.info("receiveNotify digitalEnvelope:{}", digitalEnvelope);
            log.info("receiveNotify signSN:{}", signSN);
            log.info("receiveNotify encryptSN:{}", encryptSN);
            log.info("receiveNotify signAlgorithm:{}", signAlgorithm);
            //中金回调进来的，获取机构对应的站点，设置到上下文
            if (ObjectUtils.isNotEmpty(institutionID)) {
                SupportCpcnMch cpcnMch = cpcnMchManager.getByMchId(institutionID);
                if (ObjectUtils.isEmpty(cpcnMch)) {
                    log.error("Cpcn receiveNotify institutionID:{},query cpcnMch is null ", institutionID);
                    return;
                }
                AppThreadLocal.setTenantId(cpcnMch.getTenantId());
                AppThreadLocal.setSourceCode(sourceCode);
            }
            // 证书的路径
//          String paymentConfigPath = "/cert/cpcn/" + institutionID;
            String paymentConfigPath = File.separatorChar + "app" + File.separatorChar + "cert" + File.separatorChar
                    + "cpcn" + File.separatorChar + institutionID;
            // 初始化支付环境
            try {
                log.info("临时文件夹目录地址1：{}", paymentConfigPath);
                PaymentEnvironment.initialize(paymentConfigPath);
//                ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
//                org.springframework.core.io.Resource[] resources = resolver.getResources(paymentConfigPath);
//                org.springframework.core.io.Resource resource = resources[0];
//                String absolutePath = resource.getFile().getAbsolutePath();
//                log.info("临时文件夹目录地址1：{}", absolutePath);
//                PaymentEnvironment.initialize(absolutePath);
            } catch (Exception e) {
                log.info("临时文件夹目录地址2：{}", paymentConfigPath);
                PaymentEnvironment.initialize(paymentConfigPath);
            }
            PrintWriter out = response.getWriter();
            try {
                NoticeRequest noticeRequest = new NoticeRequest(message, signature, digitalEnvelope, signSN, encryptSN, signAlgorithm);
                String txCode = noticeRequest.getTxCode();
                ReceiveNoticeEnums enums = ReceiveNoticeEnums.getByCode(txCode);
                ReceiveNoticeStrategy receiveNoticeStrategy = strategyMap.get(enums);
                receiveNoticeStrategy.handleNotice(noticeRequest);
                String base64String = new String(Base64.encode(new NoticeResponse().getMessage().getBytes(StandardCharsets.UTF_8)));
                out.print(base64String);
                out.flush();
                out.close();
            } catch (BusinessException e) {
                String resp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response version=\"2.0\"><Head><Code>" + e.getCode()
                        + "</Code><Message>" + e.getMessage() + "</Message></Head></Response>";
                out.print(new String(Base64.encode(resp.getBytes(StandardCharsets.UTF_8))));
                out.flush();
                out.close();
            }
        } catch (Exception e) {
            log.error("处理中金消息推送内容异常！error:{}", e);
        }
    }
}
